// comPort.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <string.h>
#include <stdlib.h>

#include "windows.h"
#include <vector>
#define __T(x)      L ## x 




using namespace std;

	HANDLE hPort;

int openCom(const char* port)
{
	char fileNameString[5];
	WCHAR    fileName[5];

	//Open Connection
	strcpy(fileNameString, "COM");
	strcat(fileNameString,port);
	MultiByteToWideChar( 0,0, fileNameString, 5, fileName, 5);
	if (INVALID_HANDLE_VALUE==(hPort=CreateFile(fileName,GENERIC_ALL,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0)))
    { return(GetLastError()); }

	//Setup Params
	DCB portDcb;
	memset(&portDcb,0,sizeof(portDcb)); portDcb.DCBlength=sizeof(portDcb);
	if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
	portDcb.BaudRate=38400;
	portDcb.ByteSize=8;
	portDcb.Parity=0;
	portDcb.StopBits=0;
	if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
	//setup timeouts
	 COMMTIMEOUTS commTimeOuts;
	 commTimeOuts.ReadIntervalTimeout=5;
     commTimeOuts.ReadTotalTimeoutMultiplier=5;
     commTimeOuts.ReadTotalTimeoutConstant=5;
     commTimeOuts.WriteTotalTimeoutMultiplier=10;
     commTimeOuts.WriteTotalTimeoutConstant=100;
	SetCommTimeouts(hPort,&commTimeOuts);


	return 0;
}



int closeCom()
{
	 if (hPort!=INVALID_HANDLE_VALUE) { CloseHandle(hPort); hPort=INVALID_HANDLE_VALUE; }
	 return 0;
}

void quit(int num,char* error)
{
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x4F );
	if (num!=0)
	{
		printf("\n\nError code:%d : %s", num, error);
	}
	//to prevent console close
	/*for debug*/ printf("\n\nPress enter to exit\n");	char end;	scanf("%c", &end); 
	//goto end;
}

void fileToString(std::vector<char>*  g, char* fileName)
{
	 ifstream in(fileName, ios::in | ios::binary);

	if(!in) {
	quit(-1, "not able to open input file");
	}
  
	char temp [9] = "\0";
	int read = 0;
	g->resize(1);
	(*g)[0]='\0';
	DWORD pdwRead=1;
	
	while(!in.eof())
	{
		in.read(temp,8);
		g->resize(9+read);
		temp[in.gcount()]='\0';
		strcat(&(*g)[0],temp);
		read += in.gcount();
	}  
	in.close();
	//printf("\n\n%c|\n\n",(*g)[strlen(&(*g)[0])-2]);
}




int readOld(std::vector<char>*  g)
{
//check sizes of incoming strings for validity
//Check if port exists from previous init
printf("Readold in");
	char toRead[9]="\0";
	int readLength=8;
	int read = 0;
	g->resize(1);
	(*g)[0]='\0';
	DWORD pdwRead=1;
	while(pdwRead >0)
	{
		if (!ReadFile(hPort,&toRead,readLength,&pdwRead,NULL)) return(GetLastError());
		if(pdwRead >0)
		{	
			g->resize(9+read);
			toRead[pdwRead]='\0';
			strcat(&(*g)[0],toRead);
			read += pdwRead;
		}
	}
	return 0;
}



int get(std::vector<char>*  g)
{
//TODO: Check if port exists from previous init  
char toRead[10001]="\0";
	int readLength=10000;
	int read = 0;
	g->resize(1);
	(*g)[0]='\0';
	DWORD pdwRead=1;


	char toRead1[2]="\0";
	int startedFile = 0;

	//wait for uC to start sending file
	//while(startedFile == 0)	
	//	{
	//		printf("    --waiting for start,just read|%s|",toRead);
	//		if (!ReadFile(hPort,&toRead1,1,&pdwRead,NULL)) return(GetLastError());
	//		if(toRead1[0] == '@')
	//			startedFile = 1;
	//	}
	
	//get Data

	printf("\nReceiving");
	pdwRead=1;
	int done = 0;
	while(done == 0)
	{
		if (!ReadFile(hPort,&toRead,readLength,&pdwRead,NULL)) return(GetLastError());
		if(pdwRead >0)
		{	
			g->resize(pdwRead+1+read);
			toRead[pdwRead]='\0';
			strcat(&(*g)[0],toRead);
			read += pdwRead;
		}
		
		
		//printf("      --waiting,just read %d in |%s|",read,toRead);
		printf(".");
		if(toRead[pdwRead-1]  == '&')		//& is signal from uC for transmission end
		{
			//printf("END");
			(*g)[strlen(&(*g)[0])-1] = '\0';
			done = 1;
		}
		toRead[0]='\0';	//clear the buffer string
	}
	printf("\nReceive Complete\n");

	return 0;
}




int getToFile(char* fileNameString)
{
//check sizes of incoming strings for validity
//Check if port exists from previous init

	std::vector<char> readReceived;

	ofstream out(fileNameString, ios::out | ios::binary);
	if(!out) 
	{
		quit(-4,"not able to open output file");
	}

	if(get(&readReceived) !=0)
	{ return(GetLastError()); }
//	remove and print the xxxx port:mode before data and success/fail after data and print only data(17th to (n-16) to file
	char header[19], footer[19];
	strncpy(header,&readReceived[0], 17);
	header[17] = '\0';
	strncpy(footer,&readReceived[strlen(&readReceived[0])- 16], 16);
	footer[16] = '\0';
	out.write(&readReceived[18],strlen(&readReceived[0]) - 17 - 16+1);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x2F );
	printf("%s %s",header, footer);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );
	printf("Wrote to File.\n");

	out.close();
	return 0;
}

int send(char* port, char* inaddress, char* mode, char* data)
{
//check sizes of incoming strings for validity
//Check if port exists from previous init
	int writeLength,i,j, origlength;
	char* toWrite;
	char* address;
	char numaddress[3];
	char lenData[10];


	if(strcmp(port,"INIT") == 0)	//no address or data for init
	{
		writeLength = 4;
		toWrite = (char*) malloc (writeLength);
		strcpy(toWrite, port);
	}
	else if(strcmp(port,"GPIB") == 0)	//NOTE: GPIB addresses MUST be 2 digit (i.e. 04 not 4) and comma separated
	{
		//compact addresses
		origlength = strlen(inaddress);
		address = (char*) malloc (origlength);
		j=0;
		for(i=0; i<origlength; i+=3)
		{
			address[j] = inaddress[i];
			address[j+1] = inaddress[i+1];
			j+=2;
		}
		address[j] = '\0';
	


		if(*mode == 'W')
		{
			itoa(strlen(address)/2,numaddress,10);
			itoa(strlen(data),lenData,10);
			writeLength = strlen(port) +  strlen(mode) +  strlen(numaddress) + 1 + strlen(address) + strlen(lenData) + 1 + strlen(data);
			toWrite = (char*) malloc (writeLength);
			strcpy(toWrite, port);
			strcat(toWrite, mode);
			strcat(toWrite, numaddress);
			strcat(toWrite, " ");
			strcat(toWrite, address);
			itoa(strlen(data),lenData,10);
			strcat(toWrite, lenData);
			strcat(toWrite, " ");
			strcat(toWrite, data);
		}
		else if(*mode == 'R' || *mode == 'F')
		{
			writeLength = strlen(port) +  strlen(mode) + strlen(address);
			toWrite = (char*) malloc (writeLength);
			strcpy(toWrite, port);
			strcat(toWrite, mode);
			strcat(toWrite, address);
		}
	}
	else	//no address needed for serial and parallel
	{
		writeLength = strlen(port) + strlen(data) + 1;
		toWrite = (char*) malloc (writeLength);
		strcpy(toWrite, port);
		strcat(toWrite, mode);
		if(*mode == 'W')
		{
			strcat(toWrite, data);
			if(strcmp(port,"SERL") == 0)
			{
				strcat(toWrite, "^");
				writeLength++;
			}
		}
	}
	DWORD dwWritten=0;
	int written = 0;
	int currentWrite;
	int index=0;
	printf("Sending:", writeLength);
//printf("\n\n|%c|\n\n",toWrite[strlen(toWrite)-1]);
	while(writeLength != 0)
	{
		printf(".");
		if(writeLength <100)
		{
			currentWrite = writeLength;
			writeLength = 0;
		}
		else
		{
			currentWrite = 100;
			writeLength-=100;
		}


		if (!WriteFile(hPort,&toWrite[index] ,currentWrite,&dwWritten,NULL)) return(-8);
		if (dwWritten<currentWrite) return(-9);
		index += currentWrite;
	}
	printf("Done Sending");
	return 0;
}


int sendFromFile(char* port, char* inaddress, char* mode, char* fileName)
{
	std::vector<char> fileData;
	fileToString( &fileData, fileName);
	return send(port, inaddress, mode, &fileData[0]);
}

int initPort(char* port, char* params)
{
//check sizes of incoming strings for validity (for serial: baud must be number of length<=7 and match allowed values,
	//parity must be E,O,S,M,N(for even,odd,space,mark,none), and stop must be 1,2,0,or n (0 is for 1.5, and n is for any num)
	//also all these should be comma -separated
//Check if port exists from previous init
	int writeLength;
	char* toWrite;

	if(strcmp(port,"GPIB") == 0)
	{
		writeLength = 4;
		toWrite = (char*) malloc (writeLength);
		strcpy(toWrite, "INTG");
	}
	else if(strcmp(port,"PARL") == 0)
	{
		writeLength = 7;
		toWrite = (char*) malloc (writeLength);
		strcpy(toWrite, "INTP");
//TODO: check modes for validity
		strcat(toWrite, params);
	}

	else if(strcmp(port,"SERL") == 0)
	{
		char baud[8], parity[2], stop[2];
		int i = 0;
		while(params[i] != ',')
		{
			baud[i] = params[i];
			i++;
		}
		baud[i] = '\0';
		
		parity[0] = params[i+1];
		stop[0] = params[i+3];
		parity[1] = '\0';
		stop[1] = '\0';
		writeLength = 4 + 1 + i + 2;
		toWrite = (char*) malloc (writeLength);
		strcpy(toWrite, "INTS");
		char baudlength[1];
		sprintf(baudlength, "%d", i); //length of baud string in ascii integer
//TODO: check modes for validity
		//sprintf(toWrite,"%s%s%s%c%c","INTS",baudlength,baud,params[i+1],params[i+3]);


		strcat(toWrite, baudlength);	
		strcat(toWrite, baud);
		strcat(toWrite, parity);
		strcat(toWrite, stop);
		
		printf("Sending params:%s parity is:%s, stop is:%s, params is:%s",toWrite,parity,stop, params);
		//printf("\n%s,%d",toWrite,strlen(toWrite));
	}

	DWORD dwWritten=0;
	if (!WriteFile(hPort,toWrite,writeLength,&dwWritten,NULL)) return(GetLastError());
	if (dwWritten<writeLength) return(ERROR_CAN_NOT_COMPLETE);
	

	int result;
	//Read back status and print to screen

	std::vector<char> readBuf;
	result = get(&readBuf);
	if(result !=0)
		return result;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x2F );
	printf("%s\n",&readBuf[0]);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );
	return 0;
}




int read(char* port, char* inaddress)
{
	//send request to uC
	int result = send(port,inaddress,"R" ,"");
	if(result !=0)
		return result;

	//Read back data and print to screen
	std::vector<char> readBuf;
	result = get(&readBuf);
	if(result !=0)
		return result;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x2F );
	printf("%s\n",&readBuf[0]);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );
	return 0;
}

int readToFile(char* port, char* inaddress, char* fileName)
{
	//send request to uC
	int result = send(port,inaddress,"R" ,"");
	if(result !=0)
		return result;

	//Read back data to File
	result = getToFile(fileName);
	if(result !=0)
		return result;

	return 0;
}

int write(char* port, char* inaddress, char* data)
{
	//send data to uC
	int result = send(port,inaddress,"W" ,data);
	if(result !=0)
		return result;

	//Read back status and print to screen
	std::vector<char> readBuf;
	result = get(&readBuf);
	if(result !=0)
		return result;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x2F );
	printf("%s\n",&readBuf[0]);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );
	return 0;
}

int writeFromFile(char* port, char* inaddress, char* fileName)
{
	//read and send data to uC
	int result = sendFromFile(port,inaddress,"W" ,fileName);
	if(result !=0)
		return result;

	//Read back status and print to screen
	std::vector<char> readBuf;
	result = get(&readBuf);
	if(result !=0)
		return result;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x2F );
	printf("%s\n",&readBuf[0]);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );
	return 0;
}






int _tmain(int argc, _TCHAR* argv[])
{
	char * port = "5";
	std::vector<char> readBuf;


	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 0x0F );

	//Open and setup Com Connection
	printf("PC:Connecting to board on COM%s...",port);
	if(openCom(port) !=0)
	{printf("Could not connect\n"); }
	else{
		printf("Connected\n"); 

	// initialize the board 
		if(write("INIT","","") !=0)
		{ return(GetLastError()); }
	
		
     //set the serial port at 19200 baud rate, no parity bits, 1 stop bit
			if(initPort("SERL", "19200,N,1") !=0	)
		{ quit(-6,"serial initialize failed"); }

    // wait for some time
		Sleep(2000);

	//GPIB Instrument testing: For this demo 
	// powersupply is assigned address: 02
	// oscilloscope is assigned address: 01
	// function generator is assigned address: 03
	
	// initialize the GPIB port
		if(initPort("GPIB", "") !=0)
		{ quit(-6,"GPIB initialize failed"); }

    // write *IDN ? query commands to all instruments and read the response
		if(write("GPIB","01","*IDN?") !=0)
		{ return(GetLastError()); }

		if(read("GPIB","01") !=0)
			{ return(GetLastError()); }

		if(write("GPIB","02","*IDN?") !=0)
		{ return(GetLastError()); }

		if(read("GPIB","02") !=0)
			{ return(GetLastError()); }

		if(write("GPIB","03","*IDN?") !=0)
		{ return(GetLastError()); }


		if(read("GPIB","03") !=0)
			{ return(GetLastError()); }

		//Set up the Function Generator to display a sine wave of freq 10 khz, amplitude = 3, offset =3
			
		if(write("GPIB","03","SOURCE1:FREQUENCY 10E3") !=0)
		{ return(GetLastError()); }

		
		if(write("GPIB","03","SOURCE1:VOLTAGE:AMPLITUDE 3.00") !=0)
		{ return(GetLastError()); }

		if(write("GPIB","03","SOURCE1:VOLTAGE:OFFSET 3.00") !=0)
		{ return(GetLastError()); }

		
		if(write("GPIB","03","SOURCE1:FUNCTION SIN") !=0)
		{ return(GetLastError()); }


		if(write("GPIB","03","OUTPUT ON") !=0)
		{ return(GetLastError()); }


 
      //Auto set the OSCILLOSCPE and acquire the waveform dump from channel 1
      	
		if(write("GPIB","01","AUTOSET EXECUTE") !=0)
			{ return(GetLastError()); }
				if(write("GPIB","01","ACQUIRE") !=0)
			{ return(GetLastError()); }

			//Write
			 printf("-------------\nSet channel to 1");
			 if(write("GPIB","01" ,"DAT:SOU CH1") !=0)
			{ return(GetLastError()); }
	
			Sleep(1000);
			
			if(write("GPIB","01" ,"CURV?") !=0)
			{ return(GetLastError()); }
			 
			 // send command to microcontroller to read the waveform dump
			 int result = send("GPIB","01","F" ,"");
			if(result !=0)
			return result;

			//store the waveform dump in a file
			result = getToFile("C:\\my_data.m");
			if(result !=0)
				return result;

			// send command to read the scale information
			
			if(write("GPIB","01","WFMP:YMU?") !=0)
			{ return(GetLastError()); }

			if(readToFile("GPIB","01","C:\\scale.m") !=0)
			{ return(GetLastError()); }

			// send command to read the offset information			
			if(write("GPIB","01","WFMP:YOF?") !=0)
			{ return(GetLastError()); }

			if(readToFile("GPIB","01","C:\\offset.m") !=0)
			{ return(GetLastError()); }
		
            // send command to read the delta_t information
						
			if(write("GPIB","01","WFMP:XIN?") !=0)
			{ return(GetLastError()); }

			if(readToFile("GPIB","01","C:\\delta_t.m") !=0)
		{ return(GetLastError()); }

			printf("\n******DONE Receiving Waveform**********************************");
	
	
		printf("\n\n\n\n***Ready to receive Parallel Printout****\n***Press Print Now*******************\n\n");
		
		// read the eps waveform capture from the parallel port
		if(readToFile("PARL","","C:\\parCapturefinal.eps") !=0)
		{ return(GetLastError()); }

		printf("***Parallel Receive Done***\n\n");
		Sleep(3000);

	   //SERIAL
	   // send the file just captured over parallel port to the serial port
		printf("***Starting file send over serial port***\n\n");
		if(writeFromFile("SERL","","C:\\parCapturefinal.eps"))
		{ return(GetLastError()); }

	/***************************
	
	Following code will be used if you want to send an eps file to a printer.
	
	*******************************/		
		//printf("***Parallel Port Printing***\n\n");
		//std::vector<char> parFile;		
		//fileToString( &parFile,"parCapture3.eps");

		//Write
		//printf("Printing to parallel port");
		//if(write("PARL","",&parFile[0]) !=0)


		//CloseCom
		/*for debug*/ printf("PC:Closing connection\n");
		if(closeCom() !=0)
		{ return(GetLastError()); }

	}
	
	quit(0,"");		//prompts and waits for key press to quit
	return	0;
}



